package main

import (
	"fmt"
	"io"
	"net"
	"strings"
	"sync"
	"time"
)

type Server struct {
	Ip string
	Port int

	// list online user
	OnlineMap map[string]*User
	mapLock sync.RWMutex

	// channel used for broadcast
	Message chan string
}

func NewServer(ip string, port int) *Server {
	return &Server{
		Ip: ip,
		Port: port,
		OnlineMap: make(map[string]*User),
		Message: make(chan string),
	}
}

/* when there is a msg in channel, transfer it to each user's channel in map */
func (this *Server) ListenMessage() {
	for {
		msg := <-this.Message
		this.mapLock.RLock()
		for _, cli := range this.OnlineMap {
			cli.C <- msg
		}
		this.mapLock.RUnlock()
	}
}

/* broadcast all user by put the msg into the Message channel */
func (this *Server) Broadcast(user *User, msg string) {
	sendMsg := fmt.Sprintf("[%s]%s: \n%s", user.Name, user.Addr, msg)
	this.Message <- sendMsg
}

func (this *Server) Handler(conn net.Conn) {
	fmt.Println("链接建立成功")
	conn.Write([]byte("请输入用户名:"))
	buf := make([]byte, 128)
	n, err := conn.Read(buf)
	if err != nil {
		fmt.Println("Conn Read err:", err)
		return
	}
	userName := string(buf[:n-1])
	if len(strings.Split(userName, "|")) > 1 {
		conn.Write([]byte("用户名格式错误"))
		conn.Close()
		return
	}

	user := NewUser(userName, conn, this)
	ResetChan := make(chan bool)
	
	user.Online()
	
	// client msg receiving 
	go func() {
		buf := make([]byte, 4096)
		for {
			n, err := conn.Read(buf)  // if there are no msg received, blocking
			if n == 0 {
				user.OffLine()
				return
			}

			if err != nil && err != io.EOF {
				fmt.Println("Conn Read err:", err)
				return
			}

			ResetChan <- true  // reset the time.After
			msg := string(buf[:n-1])
			user.DoMessage(msg)
		}
	}()
	
	for {
		select {
			case <-ResetChan:

			case <-time.After(time.Second * 120):
				user.SendMsg("您被踢了")
				close(ResetChan)
				conn.Close()
				return
		}
	}
}

func (this *Server) Start() {
	// socket listen
	listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", this.Ip, this.Port))
	if err != nil {
		fmt.Println("net.Listen err:", err)
		return
	}
	// close socket
	defer listener.Close()

	// go that listen Meessage
	go this.ListenMessage()

	for {
		// accept
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("listener accept err:", err)
			continue
		}
		// do handler
		go this.Handler(conn)
	}
}